<?php

/**
 * Restful参数验证类
 * 特别注意: 这里不能验证上传类字段（上传类也不会出现在restful中）
 * 
 * get|name|string|10-20|名称必须是10-20位字符串！
 * get|age|number|1-130|年龄必须在1-130岁之间！
 * post|email|regex|email|请输入正确的邮箱地址！
 * post|mark|exist|请输入简单描述！
 */
class Param {

    /**
     * 过滤所有参数
     *
     * @return void
     */
    public function filter() {
        foreach ($_GET as $k=>$v) {
            $_GET[$k] = $this->_filter($v);
        }
        foreach ($_POST as $k=>$v) {
            $_POST[$k] = $this->_filter($v);
        }
    }

    /**
     * 细致验证给定的参数
     *
     * @param array $setting 参数验证设置数组
     * @return void
     */    
    public function valid(array $setting) {
        // 遍历setting
        foreach ($setting as $k=>$v) {

            // 分解v，求出参数值、验证类型，验证设置、错误信息
            $tmp = LString::split($v, '|');
            $value = $tmp[0] == 'get' ? get($tmp[1]) : post($tmp[1]);
            $type = $tmp[2];
            $set = '';
            $msg = '';
            if ($tmp[2] != 'exist') {
                $set = $tmp[3];
                $msg = $tmp[4]; 
            } else {
                $msg = $tmp[3];
            }

            // 根据不同的类型进行不同的验证
            switch ($type) {
                case 'string':
                if (!$this->_string($value, $set)) return Section::fail($msg); 
                break;
                case 'number':
                if (!$this->_number($value, $set)) return Section::fail($msg); 
                break;
                case 'regex':
                if (!$this->_regex($value, $set)) return Section::fail($msg); 
                break;
                case 'exist':
                if (!$this->_exist($value)) return Section::fail($msg); 
                break;
                default:
                break;
            }
        }

        // 返回成功
        return Section::ok();
    }

    /**
     * 过滤单个参数字符串中的内容，并将其更改为空字符串
     *
     * @param string $src 需要过滤的源字符串
     * @return string
     */
    private function _filter(string $src) {
        $regs = [
            "/<(\\/?)(script|i?frame|style|html|body|title|link|meta|object|\\?|\\%)([^>]*?)>/isU",
            "/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
            "/select\b|insert\b|update\b|delete\b|drop\b|;|\"|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dump/is"
        ];
        $src = preg_replace($regs, '', $src);
        $src = strip_tags($src);
        return $src;
    }

    /**
     * 字符串类型验证
     *
     * @param string $src 需要验证的源字符串
     * @param string $set 验证详细参数
     * @return boolean
     */
    private function _string(string $src, string $set) {
        // 分解长度
        $tmp = LString::split($set, '-');
        $count = LString::len($src);
        $min = intval($tmp[0]);
        $max = intval($tmp[1]);
        
        // 验证字符串长度是否合适，并返回结果
        if ($count >= $min && $count <= $max) return true;
        return false;
    }

    /**
     * 数字类型验证
     *
     * @param string $src 需要验证的源字符串
     * @param string $set 验证详细参数
     * @return boolean
     */
    private function _number(string $src, string $set) {
        // 不是数字返回false
        if (!is_numeric($src)) return false;

        // 分解最小值和最大值
        $tmp = LString::split($set, '-');
        $value = floatval($src);
        $min = floatval($tmp[0]);
        $max = floatval($tmp[1]);

        // 验证数字大小是否合适，并返回结果
        if ($value >= $min && $value <= $max) return true;
        return false;
    }

    /**
     * 正则表达式类型验证
     *
     * @param string $src 需要验证的源字符串
     * @param string $set 验证详细参数
     * @return boolean
     */
    private function _regex(string $src, string $set) {
        return LRegex::match($src, $set);
    }

    /**
     * 存在类型验证
     *
     * @param string $src 需要验证的源字符串
     * @return boolean
     */
    private function _exist(string $src) {
        if ($src == '') return false;
        return true;
    }
}
